package com.xinxin.base.util;

import com.google.common.base.Stopwatch;
import com.google.common.collect.Sets;

import java.time.LocalDateTime;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.CompletableFuture;
import java.util.stream.IntStream;

/**
 * @author ys
 * @date 2021/6/4
 */
public class NumberUtil {

    private static final String C_CODES_STRING = "0123456789ABCDEFGHJKLMNPQRSTVWXY";

    /**
     * 生成单号：13位时间戳 + 2位随机数 + 4位附加 = 19位
     * 理论每秒每账户 90（随机）* 1000（毫秒）= 90,000 个
     * 实测 8线程并发1,000,000 次 4秒内生成 32W 左右
     *
     * @param accountId 账户id
     */
    public static Long genOrderNo(Long accountId) {
        // 时间精度到分钟
        String dateTime = DateTimeUtil.formatTime(LocalDateTime.now(), "yyyyMMddHHmm");

        // 随机数 2位共 90个
        String random = CommonUtil.generateCode(10, 99);

        // 账户id后4位逆序
        StringBuilder attach = new StringBuilder();
        char[] chars = accountId.toString().toCharArray();
        for (int i = chars.length - 1; i > chars.length - 5; i--) {
            attach.append(chars[i]);
        }

        return Long.valueOf(System.currentTimeMillis() + random + attach.toString());
    }

    public static String baseConvert(String s, int srcBase, int destBase) {
        if (srcBase == destBase) {
            return s;
        }

        if (destBase != 10) {
            return baseConvert(Long.valueOf(baseConvert(s, srcBase, 10)), destBase);
        }

        char[] chars = s.toCharArray();
        int length = chars.length;
        long dec = 0;
        for (int i = length - 1; i >= 0; i--) {
            dec += C_CODES_STRING.indexOf(chars[i]) * Math.pow(srcBase, length - i - 1);
        }

        return String.valueOf(dec);
    }

    public static String baseConvert(long number, int base) {
        if (base > C_CODES_STRING.length()) {
            return "";
        }

        Stack<String> stack = new Stack<>();
        while (number != 0) {
            stack.push(C_CODES_STRING.charAt((int) (number % base)) + "");
            number /= base;
        }

        StringBuilder sb = new StringBuilder();
        while (!stack.empty()) {
            sb.append(stack.pop());
        }

        return sb.toString();
    }

    public static void main(String[] args) throws Exception {
        String s = NumberUtil.baseConvert(255L, 2);
        System.out.println(s);
        s = NumberUtil.baseConvert(s, 2, 10);
        System.out.println(s);

        s = NumberUtil.baseConvert(10000016L, 32);
        System.out.println(s);
        s = NumberUtil.baseConvert(s, 32, 10);
        System.out.println(s);

        s = NumberUtil.baseConvert("YYYYY", 32, 10);
        System.out.println(s);
        s = NumberUtil.baseConvert("YYYYYY", 32, 10);
        System.out.println(s);
        s = NumberUtil.baseConvert("1000000", 32, 10);
        System.out.println(s);

        s = NumberUtil.genOrderNo(10000016L).toString();
        System.out.println(s);

        Set<Long> set = Sets.newConcurrentHashSet();
        CompletableFuture<Void> future = CompletableFuture.completedFuture(null);
        Stopwatch stopwatch = Stopwatch.createStarted();
        for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) {
            future = CompletableFuture.allOf(future,
                    CompletableFuture.runAsync(() -> IntStream.range(1, 1_000_000)
                            .forEach(j -> set.add(NumberUtil.genOrderNo(10000016L))))
            );
        }
        future.get();
        System.out.println(set.size() + " " + stopwatch.stop().toString());
    }
}
